package com.cedric.handler;

import com.alibaba.fastjson.JSON;
import com.cedric.component.DelayBucket;
import com.cedric.component.JobPool;
import com.cedric.component.ReadyQueue;
import com.cedric.constants.DelayConfig;
import com.cedric.constants.JobStatus;
import com.cedric.entity.DelayJob;
import com.cedric.entity.Job;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

/**
 * @program: delay-queue
 * @description:
 * @author: 史偕成
 * @create: 2021/09/26 21:46
 **/
@Slf4j
@AllArgsConstructor
public class DelayJobHandle implements Runnable {
    /**
     * 延迟队列
     */
    private DelayBucket delayBucket;

    /**
     * 任务池
     */
    private JobPool jobPool;

    /**
     *
     */
    private ReadyQueue readyQueue;

    /**
     * 索引
     */
    private int index;

    @Override
    public void run() {
        log.info("[定时任务开始了]");
        while (true) {
            try {
                DelayJob delayJob = delayBucket.getFirstDelayTime(index);
                //没有任务
                if (delayJob == null) {
                    sleep();
                    continue;
                }
                // 发现延时任务
                // 延迟时间没到
                if (delayJob.getDelayDate() > System.currentTimeMillis()) {
                    sleep();
                    continue;
                }
                Job job = jobPool.getJob(delayJob.getJodId());
                //延迟任务元数据不存在
                if (job == null) {
                    log.info("移除不存在任务:{}", JSON.toJSONString(delayJob));
                    delayBucket.removeDelayTime(index,delayJob);
                    continue;
                }
                JobStatus status = job.getStatus();
                if (JobStatus.RESERVED.equals(status)) {
                    log.info("处理超时任务:{}", JSON.toJSONString(job));
                    // 超时任务
                    processTtrJob(delayJob,job);
                } else {
                    log.info("处理延时任务:{}", JSON.toJSONString(job));
                    // 延时任务
                    processDelayJob(delayJob,job);
                }
            } catch (Exception e) {
                log.error("扫描DelayBucket出错",e);
                sleep();
            }
        }
    }

    /**
     * 处理超时任务
     * @param delayJob
     * @param job
     */
    private void processTtrJob(DelayJob delayJob, Job job) {
        job.setStatus(JobStatus.DELAY);
        // 修改任务池状态
        jobPool.addJob(job);
        // 移除delayBucket中的任务
        delayBucket.removeDelayTime(index,delayJob);
        long delayDate = System.currentTimeMillis() + job.getDelayTime();
        delayJob.setDelayDate(delayDate);
        // 再次添加到任务中
        delayBucket.addDelayJob(delayJob);
    }

    /**
     * 处理延时任务
     * @param delayJob
     * @param job
     */
    private void processDelayJob(DelayJob delayJob, Job job) {
        job.setStatus(JobStatus.READY);
        // 修改任务池状态
        jobPool.addJob(job);
        // 设置到待处理任务
        readyQueue.pushJob(delayJob);
        // 移除delayBucket中的任务
        delayBucket.removeDelayTime(index,delayJob);
    }


    /**
     * 线程睡眠
     */
    private void sleep() {
        try {
            Thread.sleep(DelayConfig.SLEEP_TIME);
        } catch (Exception e) {
            log.error("线程睡眠失败");
        }

    }
}
